package com.ly.websocket.web;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import com.ly.websocket.bean.WebSocketProperties;
import com.ly.websocket.biz.IMsgSender;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.websocket.*;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import java.io.IOException;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Collectors;

@RequestMapping("ws")
@RestController
@ServerEndpoint("/ws/{id}")
public class WebSocketDo {

    // websocket 每次连接成功都会创建新的 WebSocketDo 对象
    // spring 不会注入静态属性
    static WebSocketProperties properties;
    static IMsgSender msgSender;
    static JdbcTemplate jdbc;

    @RequestMapping("config")
    WebSocketProperties properties(){
        return properties;
    }

    @Autowired
    public WebSocketDo(IMsgSender msgSender, WebSocketProperties properties,
                       JdbcTemplate jdbc) {
        WebSocketDo.msgSender = msgSender;
        WebSocketDo.properties = properties;
        WebSocketDo.jdbc = jdbc;
    }

    public WebSocketDo(){ }

    // websocket 会为每个连接成功客户端创建一个 talkdo 对象
    // 在線用戶容器
    private static Map<String, Session> onlines = new ConcurrentHashMap<>();

    @OnOpen
    public void onOpen(Session session, @PathParam("id") String id) throws Exception {
        Object userinfo = getUserInfoById(id);
        session.getUserProperties().put("id",userinfo);
        onlines.put(id, session);
        Msg msg = buildMsg(userinfo, "上线了", true);
        msgSender.send(msg);
    }

    @OnClose
    public void onClose(Session session) throws Exception {
        Map<String,Object> userinfo = (Map<String, Object>) session.getUserProperties().get("id");
        /**
         * userinfo 里面的 id 是 int 类型,  无法使用 userinfo.id get 或 remove  onlines 的元素
         */
        onlines.remove(userinfo.get(properties.getKeyColumn()) + "");
        Msg msg = buildMsg(userinfo, "下线了", true);
        msgSender.send(msg);
    }

    @OnError
    public void onError(Session session, Throwable throwable){
        System.out.println("会话异常: " + throwable);
    }

    @OnMessage
    public void onMessage(Session session, String message) throws Exception {
        Object userinfo = session.getUserProperties().get("id");
        Msg msg = buildMsg(userinfo, message, false);
        msgSender.send(msg);
    }

//    private void sendAllMsg(String message){
//        onlines.values().forEach(s->{
//            try {
//                s.getBasicRemote().sendText(message);
//            } catch (IOException e) {
//                throw new RuntimeException("发送消息失败!", e);
//            }
//        });
//    }

    // 转json的代码已经转到 DefaultMsgSender ,  objectMapper 不要了
    // ObjectMapper objectMapper = new ObjectMapper();

    public Msg buildMsg(Object author, String content, boolean isSendOnlines){
        Msg msg = new Msg(author, content, null);
        if(isSendOnlines == true){
            List<Object> onlinesMap = onlines.values()
                    .stream()
                    .map(session -> session.getUserProperties().get("id"))
                    .collect(Collectors.toList());
            msg.onlines = onlinesMap;
        }
        return msg;
    }

    @Data
    @AllArgsConstructor
    @NoArgsConstructor
    public static class Msg{
        // 发送人
        Object author;
        // 内容
        String content;
        // 在线人员列表
        List<Object> onlines;
    }

    // 获取在线人数集合
    public static Map<String, Session> getOnlines() {
        return onlines;
    }

    private Object getUserInfoById(String id) {
        String sql = "select * from %s where %s = ?";
        sql = String.format(sql, properties.getUserTable(), properties.getKeyColumn());
        Map<String, Object> userinfo = jdbc.queryForMap(sql, id);
        return userinfo;
    }
}


